package common

import (
	"fmt"
	// "math"
	"regexp"
	"sort"
	"strconv"
	"time"
)

type TimeUnit uint32

const (
	OneDay = int32(24 * 3600)
)

var pattern = regexp.MustCompile(`/*(\d{10}):(\d+)$`)

func NewTimeUnit(i int) (TimeUnit, error) {
	j := int32(i)
	if OneDay > j && OneDay%j != 0 {
		return 0, fmt.Errorf("invalid unit to split one day")
	}
	if OneDay < j && j%OneDay != 0 {
		return 0, fmt.Errorf("invalid unit to split multi day")
	}
	return TimeUnit(i), nil
}

func (tu TimeUnit) GetTimeSplit(timestamp uint32) (TimeSplit, int) {
	if OneDay > int32(tu) {
		r := int32(timestamp) % OneDay
		offset := r % int32(tu)
		base := int32(timestamp) - offset
		return TimeSplit{base, tu}, int(offset)
	}
	r := int32(timestamp) % int32(tu)
	base := int32(timestamp) - r
	return TimeSplit{base, tu}, int(r)
}

func (tu TimeUnit) GetTimeSplits(from, to uint32) (ret []TimeSplit) {
	if to == 0 {
		to = uint32(time.Now().Unix())
	}
	if to <= from {
		return
	}
	v, _ := tu.GetTimeSplit(from)
	ret = append(ret, v)
	t, _ := tu.GetTimeSplit(to + uint32(tu))
	for v.base+int32(tu) < t.base {
		v, _ = tu.GetTimeSplit(uint32(v.base) + uint32(tu))
		ret = append(ret, v)
	}
	return
}

type TimeSplit struct {
	base int32
	unit TimeUnit
}

func (t *TimeSplit) CompareToNow() int {
	v, _ := t.unit.GetTimeSplit(uint32(time.Now().Unix()))
	return t.CompareTo(v)
}

func (t *TimeSplit) CompareTo(other TimeSplit) int {
	return int((t.base - other.base) / int32(t.unit))
}

func (t *TimeSplit) Contains(ts uint32) bool {
	return ts >= uint32(t.base) && ts < uint32(t.base)+uint32(t.unit)
}

func (t *TimeSplit) IsInRange(a, b uint32) bool {
	return b >= uint32(t.base) && a <= uint32(t.base)+uint32(t.unit)
}

func (t *TimeSplit) IsSameSplit(a, b uint32) bool {
	r, _ := t.unit.GetTimeSplit(a)
	l, _ := t.unit.GetTimeSplit(b)
	return r == l
}

func (t TimeSplit) String() string {
	return fmt.Sprintf("%d:%d", t.base, t.unit)
}

func ParseTimeSplit(s string) (ts TimeSplit, err error) {
	match := pattern.FindStringSubmatch(s)
	if len(match) != 3 {
		err = fmt.Errorf("match error")
		return
	}
	i, err := strconv.Atoi(match[1])
	if err != nil {
		return
	}
	j, err := strconv.Atoi(match[2])
	if err != nil {
		return
	}
	u, err := NewTimeUnit(j)
	if err != nil {
		return
	}
	return TimeSplit{int32(i), u}, nil
}

type TimeSplits []TimeSplit

func (t TimeSplits) CheckOverlapsAndHoles() int {
	sort.Sort(t)
	var p int32
	for _, i := range t {
		if p != 0 && p != i.base {
			return int(p - i.base)
		}
		p = i.base + int32(i.unit)
	}
	return 0
}

func (t TimeSplits) Len() int {
	return len(t)
}

func (t TimeSplits) Swap(i, j int) {
	t[i], t[j] = t[j], t[i]
}
func (t TimeSplits) Less(i, j int) bool {
	return t[i].base < t[j].base
}
